-
Notifications
You must be signed in to change notification settings - Fork 322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CIP-???? | SpendMany script purpose (replace Spend) #858
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible for users to specify multiple spendMany
groups for the same script in a single transaction? For example, perhaps they want to sub-divide a group of inputs being spent by a single script (possibly by redeemer used).
|
||
SpendMany is executed only once for the whole transaction and it comes with 2 parameters: | ||
- The current script hash | ||
- The list of the indexes of the inputs that are being spent from this script |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some scripts allow composing with itself where inputs use different redeemers. It sounds like this CIP will require all inputs from the script in this transaction to use the same redeemer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the current CIP version requires 1 redeemer for all the inputs from the smart contract.
Can't we just use a single redeemer that contains lists for each field, indexed by the order of the inputs?
We already do like that and it works smoothly: as we know the inputs and their order in advance, it's easy to setup such a redeemer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just use a single redeemer that contains lists for each field, indexed by the order of the inputs?
I'd rather not use the redeemer like this since it must always be validated at run-time to verify all of the inputs are properly accounted for. If an input is accidentally/maliciously omitted from the redeemer, the smart contract can return true without actually validating that input. In other words, the security of this approach depends on the DApp developer. It is possible for one DApp to be secure while another DApp is missing checks.
Instead, the ledger can do the checks before running the scripts if separate spending groups are used. One of the plutus/ledger devs can correct me if I am wrong, but if the rule is that all inputs in a spending group must use the same redeemer, wouldn't this be a very cheap check that can be part of phase 1 validation? You can just hash the redeemer used for each input in the group and then compare the hashes. If an input is not tagged by a redeemer, the ledger will immediately catch it and fail the transaction.
I have not used the redeemer index pattern very much, so if I am misunderstanding something please correct me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @matteocoppola - putting on agenda to introduce at next CIP meeting, as titled in the document without the "replace" clause (which might be debatable): https://hackmd.io/@cip-editors/93 - you would be very welcome at the meeting.
We should eventually make the PR & document titles consistent, but in the meantime I think it helps to have (replace Spend)
in the PR title to call attention to this fact. I don't have the skill set to suggest whether Spend
and SpendMany
could or should coexist but I think it would be a good discussion point for the meeting.
|
||
Even if it's not a dependency, this CIP works very well with the [CIP for Transaction Inputs as Unordered Set](https://github.com/cardano-foundation/CIPs/pull/758). | ||
|
||
Even if this CIP looks as an alternative to [CIP-112](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0112), they can perfectly co-exist. Additionally this CIP drastically simplifies the development experience. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if this CIP looks as an alternative to [CIP-112](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0112), they can perfectly co-exist. Additionally this CIP drastically simplifies the development experience. | |
Even if this CIP looks as an alternative to [CIP-112 | Observe Script Type](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0112), they can perfectly co-exist. Additionally this CIP drastically simplifies the development experience. |
just helps for those who struggle to remember every number 😆
## Rationale: how does this CIP achieve its goals? | ||
|
||
This CIP removes the need of unprofessional hacks to achieve whole-transaction validation while also achieving better computational efficiency. | ||
A simple chnage of the Spend purpose in SpendMany can simplify the developer experience, giving visibility of all the inputs to validate at once. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A simple chnage of the Spend purpose in SpendMany can simplify the developer experience, giving visibility of all the inputs to validate at once. | |
A simple change of the Spend purpose in SpendMany can simplify the developer experience, giving visibility of all the inputs to validate at once. |
typo!
@matteocoppola following up from my #858 (review) from CIP meeting today (re: does Consensus is that Ledger input (cc @lehins @WhatisRT) is needed to decide how to go ahead with this. Everyone agrees the newly defined purpose is an improvement on the old one, with the old use cases being definable with the new script purpose, but can't be sure if there aren't "edge cases" that would break backwards compatibility: and therefore a requirement for versioning and/or supporting both the old & new script purpose. Because of this question of scope, as well as feasibility of doing this in the Ledger, we've decided to wait for Ledger's initial feedback with some kind of endorsement before assigning this a candidate CIP number. Once we get to this stage I'll be sure it's on the next CIP meeting agenda. |
I'll need to think a bit more about this, but my first thoughts are that this is a great idea. The issue with the redeemer is a bit bigger though, since Ledger also needs to match redeemers to inputs. One idea would be to allow an input to be a list of inputs locked by the same script. Then one can still run the same script with different redeemers while the logic that matches redeemers could be unchanged. |
This is definitely a sensible proposal. That being said, we can't do this change for PlutusV1..PlutusV3, since we can't change the context for those versions and addition of a new script purpose is a change to the plutus context. So, we can't "replace Spend", as the title suggests. But, that doesn't mean we can't implement it for PlutusV4. In the matter of fact, I just made a comment on another CIP that we could solve those two proposals with the same solution. New script purpose could look something like this for plutus: PV4.SpendingMany [(Integer, TxIn)] where While for Ledger's redeemer pointer/plutus purpose (i.e. Ledger's script purpose) would look like this: SpendingMany (Set Word32) There are a few issues that come with this approach off top my head, neither of which might be an actual problem, but something developers and users need to be aware of. In all of the examples below I assume all inputs are locked by the same script, which would be enforced by ledger:
Map.fromList [(SpendingMany [1,2,3], (_ :: Data, ExUnits 123 456))]
Map.fromList
[ (SpendingMany [1,2], (a :: Data, ExUnits 123 456)
, (SpendingMany [3], (b :: Data, ExUnits 1230 4560)
]
Map.fromList
[ (SpendingMany [1,2], (a :: Data, ExUnits 123 456)
, (SpendingMany [1,3], (b :: Data, ExUnits 1230 4560) In this example the script that locks input |
@lehins My first thought is I'd be concerned of this increasing the double satisfaction attack surface. From a smart contract's perspective, I don't see how this is different than double spending the input. DApps that don't want this behavior would likely need extra logic to account for the same input being used to satisfy two separate script executions. In other words, these DApps would be burdened by these extra checks just to support the DApps that actually want this behavior. I think this feature will likely be too niche to impose this burden on the remaining DApps. I would rather the ledger disallow this feature by guaranteeing an input gets exactly one script execution. |
@matteocoppola it's noted by @fallen-icarus (#418 (comment)) that this should be considered a solution for candiate CPS-0004. By convention that CIP & CPS would be linked in the header & CIP Rationale so please keep that in mind for future revisions as these documents evolve. |
This CIP proposes to replace the current Spend purpose with another one called SpendMany, removing the need of computational waste and higher fees when a transaction validates multiple inputs coming from the same script.
If adopted, Cardano smart contract development would be more efficient, less prone to security issues and easier from a Dev experience.
(rendered proposal in branch)